﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;   //   for Texture2D
using Microsoft.Xna.Framework;  //  for Vector2


using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace RisingThreat
{
    class Player
    {
        public Steering steer { get; set; }
        public Model player;
        public float scale = 0.03f;
        public Bullet[] bullets = new Bullet[5];
        public bool isAlive = true;

        public BoundingSphere bounding;

        public Player(Vector3 newPosition, Model p, Model b)
        {
            player = p;

            steer = new Steering(newPosition + new Vector3(0.0f, 1.0f, 0.0f), new Vector3(0.0f, 0.0f, 0.0f), new Vector3(0f, 0f, 0f), 0, 0, 0, new Vector3(2.5f, 0, 2.5f), new Vector3(5.0f, 0.0f, 5.0f), 40.0f, 20.0f);

            bounding.Center = steer.position;
            bounding.Radius = 0.6f; //random

            for (int i = 0; i != 5; i++)
            {
                bullets[i] = new Bullet(b);
            }
        }

        /*
        public void Draw(GraphicsDeviceManager graphics, Matrix view, Matrix projection)
        {
            foreach (ModelMesh mesh in player.Meshes)
            {
                foreach (BasicEffect effect in mesh.Effects)
                {
                    effect.EnableDefaultLighting();
                    effect.PreferPerPixelLighting = true;

                    effect.World =  
                        Matrix.CreateFromYawPitchRoll(
                        MathHelper.PiOver2 + steer.orientation,
                        MathHelper.PiOver2,
                        MathHelper.Pi) *
                         Matrix.CreateScale(scale) *
                        Matrix.CreateTranslation(steer.position);

                    effect.Projection = projection;
                    effect.View = view;
                }
                mesh.Draw();
            }
        }
         */

        public void Draw(GraphicsDeviceManager graphics, Matrix view, Matrix projection)
        {
            if (isAlive)
            {
                // DRAW player
                // Copy any parent transforms.
                Matrix[] transforms = new Matrix[player.Bones.Count];
                player.CopyAbsoluteBoneTransformsTo(transforms);

                // Draw the model. A model can have multiple meshes, so loop.


                foreach (ModelMesh mesh in player.Meshes)
                {


                    // This is where the mesh orientation is set, as well 
                    // as our camera and projection.
                    foreach (BasicEffect effect in mesh.Effects)
                    {
                        effect.EnableDefaultLighting();

                        effect.PreferPerPixelLighting = true;

                        effect.World =transforms[mesh.ParentBone.Index]* Matrix.CreateScale(scale)*
                            Matrix.CreateFromYawPitchRoll(
                                MathHelper.PiOver2 + steer.orientation,
                                MathHelper.Pi,
                                MathHelper.Pi) *
                            Matrix.CreateTranslation(new Vector3(steer.position.X, 0.2f, steer.position.Z));

                        if (steer.health <= 0)
                        {

                            effect.World =
                                Matrix.CreateFromYawPitchRoll(
                                MathHelper.PiOver2 + steer.orientation,
                                MathHelper.Pi,
                                MathHelper.Pi) *
                                 Matrix.CreateScale(scale) *
                                Matrix.CreateTranslation(steer.position+Vector3.Down/2);
                        }

                        effect.Projection = projection;
                        effect.View = view;
                    }
                    // Draw the mesh, using the effects set above.
                    mesh.Draw();
                }
            }
        }

        public void update(GameTime time, Level level)
        {
            if (steer.health > 0)
            {
                bounding.Center = steer.position;
                bounding.Center.Y = 1.0f;
                CheckForCollisions(level);
                steer.position.Y = 1.0f;//Y value clamp
                bounding.Center.Y = 1.0f;
                foreach (Bullet bullet in bullets)
                {
                    if (bullet.isAlive)
                    {
                        bullet.Update(time, level);
                    }
                }
            }
        }

        public void CheckForCollisions(Level level)
        {
            CollisionDetector cd = new CollisionDetector();
            HashSet<QuadTreeItem> hashie = level.getPotentialCollisions(bounding);

            List<QuadTreeItem> collisions = cd.detectLevelCollisions(bounding, hashie);
            foreach (QuadTreeItem item in collisions)
            {

                if(bounding.Intersects(item.getBoundingVolume()))
                {
                    ResolveCollisionBVH(item);
                }
            }
        }

        public void ResolveCollisionBVH(QuadTreeItem item)
        {
            BoundingBox itemBound = new BoundingBox(item.getBoundingVolume().Min, item.getBoundingVolume().Max);
            Vector3 itemBoundCenter = new Vector3((itemBound.Min.X + itemBound.Max.X) / 2, 1.5f, (itemBound.Min.Z + itemBound.Max.Z) / 2);

            if ((this.steer.position.X > (itemBound.Min.X - this.bounding.Radius / 2)) && this.steer.position.X < (itemBound.Max.X + this.bounding.Radius / 2))
            {
                if (this.steer.position.Z > itemBoundCenter.Z)
                {
                    Vector3 contactNorm = new Vector3(0, 0, -1);
                    contactNorm.Normalize();
                    //contact position is implied with intersecting spheres
                    //calculate seperation velocity
                    Vector3 seperationVelocity = (this.steer.velocity);
                    seperationVelocity = seperationVelocity * contactNorm;
                    //use a coefficient of impulse
                    seperationVelocity *= 1.5f;
                    //apply impulse
                    this.steer.velocity += seperationVelocity;
                    //added code to make things smoother; so my code uses projection as well as impulses.
                    this.steer.position.Z = (itemBound.Max.Z + this.bounding.Radius);
                }
                else
                {
                    Vector3 contactNorm = new Vector3(0, 0, -1);
                    contactNorm.Normalize();
                    //contact position is implied with intersecting spheres
                    //calculate seperation velocity
                    Vector3 seperationVelocity = (this.steer.velocity);
                    seperationVelocity = seperationVelocity * contactNorm;
                    //use a coefficient of impulse
                    seperationVelocity *= 1.5f;
                    //apply impulse
                    this.steer.velocity += seperationVelocity;
                    //added code to make things smoother; so my code uses projection as well as impulses.
                    this.steer.position.Z = (itemBound.Min.Z - this.bounding.Radius);
                }
            }
            else
            {
                if (this.steer.position.X > itemBoundCenter.X)
                {
                    Vector3 contactNorm = new Vector3(-1, 0, 0);
                    contactNorm.Normalize();
                    //contact position is implied with intersecting spheres
                    //calculate seperation velocity
                    Vector3 seperationVelocity = (this.steer.velocity);
                    seperationVelocity = seperationVelocity * contactNorm;
                    //use a coefficient of impulse
                    seperationVelocity *= 1.5f;
                    //apply impulse
                    this.steer.velocity += seperationVelocity;
                    //added code to make things smoother; so my code uses projection as well as impulses.
                    this.steer.position.X = (itemBound.Max.X + this.bounding.Radius);
                }
                else
                {
                    Vector3 contactNorm = new Vector3(-1, 0, 0);
                    contactNorm.Normalize();
                    //contact position is implied with intersecting spheres
                    //calculate seperation velocity
                    Vector3 seperationVelocity = (this.steer.velocity);
                    seperationVelocity = seperationVelocity * contactNorm;
                    //use a coefficient of impulse
                    seperationVelocity *= 1.5f;
                    //apply impulse
                    this.steer.velocity += seperationVelocity;
                    //added code to make things smoother; so my code uses projection as well as impulses.
                    this.steer.position.X = (itemBound.Min.X - this.bounding.Radius);
                }
            }
        }

        public void Shoot()
        {
            foreach(Bullet bullet in bullets)
            {
                if(!bullet.isAlive)
                {
                    bullet.isAlive=true;
                   // bullet.steer.position+=Vector3.Up; // make bullet alligned with gun
                    bullet.velocity = -GameScreen.camera.camDir *bullet.speed;
                    bullet.velocity.Y = 0.0f;
                    bullet.position = steer.position;
                    bullet.orientation = steer.orientation;
                    break;
                }
            }
        }

    }
}
